//
//  MetalView.m
//  learn-metal
//
//  Created by LimitLiu on 2019/1/29.
//  Copyright © 2019 LimitLiu. All rights reserved.
//

#import "MetalView.h"
#import <simd/simd.h>
#import "binding.h"

typedef struct {
    vector_float2 position;
    vector_float4 color;
} Vertex;

@interface MetalView ()

@property(nonatomic, strong) id<MTLCommandQueue> commandQueue;
@property(nonatomic, strong) id<MTLRenderPipelineState> pipelineState;
@property(nonatomic, strong) CADisplayLink *display;

@end

@implementation MetalView

#pragma mark getter

- (CAMetalLayer *)mLayer {
    return (CAMetalLayer *) self.layer;
}

#pragma mark initialize methods

+ (Class)layerClass {
    return CAMetalLayer.class;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        self.commandQueue = command_queue(self.mLayer);
        id<MTLDevice> device = self.mLayer.device;
        id<MTLLibrary> library = device.newDefaultLibrary;
        id<MTLFunction> vert = [library newFunctionWithName:@"vertexShader"];
        id<MTLFunction> frag = [library newFunctionWithName:@"fragmentShader"];
        self.pipelineState = prepare_pipeline_state(device, vert, frag);
    }
    return self;
}

- (void)setFrame:(CGRect)frame {
    [super setFrame:frame];
    CGFloat scale = [UIScreen mainScreen].scale;
    if (self.window) {
        scale = self.window.screen.scale;
    }
    CGSize drawableSize = self.bounds.size;
    drawableSize.width *= scale;
    drawableSize.height *= scale;
    self.mLayer.drawableSize = drawableSize;
}

- (void)dealloc {
    [_display invalidate];
}

- (void)didMoveToSuperview {
    [super didMoveToSuperview];
    if (self.superview) {
        self.display = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayDidFire)];
        [self.display addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    } else {
        [self.display invalidate];
        self.display = nil;
    }
}

- (void)displayDidFire {
    id<MTLDevice> device = self.mLayer.device;
    static const Vertex vertex_data[] = {
        { {  0.5, -0.5 }, { 1, 0, 0, 1 } },
        { { -0.5, -0.5 }, { 0, 1, 0, 1 } },
        { {  0.0,  0.5 }, { 0, 0, 1, 1 } },
    };
    id<MTLBuffer> vBuf = [device newBufferWithBytes:vertex_data length:sizeof(vertex_data) options:MTLResourceCPUCacheModeDefaultCache];
    re_draw(self.mLayer, _commandQueue, _pipelineState, vBuf);
}

@end
